package com.huixi.microspur.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huixi.microspur.commons.page.PageData;
import com.huixi.microspur.commons.page.PageFactory;
import com.huixi.microspur.web.mapper.WjAppealMapper;
import com.huixi.microspur.web.pojo.dto.appeal.WjAppealPageDTO;
import com.huixi.microspur.web.pojo.dto.appeal.WjAppealPageNearbyDTO;
import com.huixi.microspur.web.pojo.entity.appeal.*;
import com.huixi.microspur.web.pojo.entity.chat.WjChat;
import com.huixi.microspur.web.pojo.entity.user.WjUser;
import com.huixi.microspur.web.pojo.vo.appeal.QueryAppealByIdVo;
import com.huixi.microspur.web.pojo.vo.appeal.QueryAppealVO;
import com.huixi.microspur.web.pojo.vo.appeal.QueryNearbyAppealVO;
import com.huixi.microspur.web.service.*;
import com.huixi.microspur.web.util.CommonUtil;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 诉求表 服务实现类
 * </p>
 *
 * @author xzl
 * @since 2020-01-17
 */
@Service
public class WjAppealServiceImpl extends ServiceImpl<WjAppealMapper, WjAppeal> implements WjAppealService {

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private WjAppealEndorseService wjAppealEndorseService;

    @Resource
    private WjUserService wjUserService;

    @Resource
    private WjAppealMaterialService wjAppealMaterialService;

    @Resource
    private WjAppealTagService wjAppealTagService;

    @Resource
    private WjChatService wjChatService;

    @Resource
    private WjAppealCommentService wjAppealCommentService;


    @Override
    public QueryAppealByIdVo queryByAppealId(String appealId) {

        QueryAppealByIdVo queryAppealByIdVo = new QueryAppealByIdVo();

        WjAppeal byId = getById(appealId);

        BeanUtil.copyProperties(byId, queryAppealByIdVo);

        // 查询发帖人用户信息
        WjUser entity = wjUserService.lambdaQuery().eq(WjUser::getUserId, byId.getUserId()).one();
        queryAppealByIdVo.setNickName(entity.getNickName())
                .setHeadPortrait(entity.getHeadPortrait());

        // 获取诉求的点赞数
        Integer endorseCount = wjAppealEndorseService.lambdaQuery()
                .eq(WjAppealEndorse::getAppealId, byId.getAppealId()).count();
        queryAppealByIdVo.setEndorseCount(endorseCount);

        // 获取诉求评论次数
        Integer commentCount = wjAppealCommentService.lambdaQuery()
                .eq(WjAppealComment::getAppealId, byId.getAppealId()).count();
        queryAppealByIdVo.setCommentCount(commentCount);

        // 获取评论人的头像
        Page<WjAppealComment> commentPage = wjAppealCommentService.lambdaQuery()
                .eq(WjAppealComment::getAppealId, byId.getAppealId())
                .orderByDesc(WjAppealComment::getCreateTime)
                .page(new Page<>(1, 3));
        List<String> commentUserIds =
                commentPage.getRecords().stream().map(e -> e.getUserId()).collect(Collectors.toList());
        List<String> headPortraitList = new ArrayList<>();
        if (commentUserIds.size() != 0) {
            headPortraitList = wjUserService.lambdaQuery()
                    .in(WjUser::getUserId, commentUserIds)
                    .list().stream().map(e -> e.getHeadPortrait()).collect(Collectors.toList());
        }


        // 前三的头像
        queryAppealByIdVo.setCommentUserHeadPortrait(headPortraitList);


        // 诉求的素材
        List<WjAppealMaterial> materialList = wjAppealMaterialService.lambdaQuery()
                .eq(WjAppealMaterial::getAppealId, byId.getAppealId()).list();
        queryAppealByIdVo.setAppealMaterial(materialList);

        // 诉求标签
        List<WjAppealTag> tagList = wjAppealTagService.lambdaQuery()
                .eq(WjAppealTag::getAppealId, byId.getAppealId()).list();
        queryAppealByIdVo.setAppealTag(tagList);

        // 查询是否点赞
        List<WjAppealEndorse> list = wjAppealEndorseService.lambdaQuery()
                .eq(WjAppealEndorse::getAppealId, byId.getAppealId())
                .eq(WjAppealEndorse::getUserId, CommonUtil.getNowUserId()).list();

        queryAppealByIdVo.setIsEndorse(list.size() != 0);


        return queryAppealByIdVo;
    }

    /**
     * 按条件分页查询 诉求
     *
     * @param wjAppealPageDTO
     * @return
     * @Author 叶秋
     * @Date 2020/2/26 21:14
     **/
    @Override
    public PageData listPageAppeal(WjAppealPageDTO wjAppealPageDTO) {

        // 最终传过去的值
        PageData pageData = new PageData();

        List<QueryAppealVO> queryAppealVOList = new ArrayList<>();

        // 分页参数
        Page<WjAppeal> page = PageFactory.createPage(wjAppealPageDTO.getPageQuery());
        // 按照创建时间/点赞量顺序来查询
        LambdaQueryWrapper<WjAppeal> objectQueryWrapper = Wrappers.<WjAppeal>lambdaQuery()
                .like(StrUtil.isNotBlank(wjAppealPageDTO.getTitle()), WjAppeal::getTitle, wjAppealPageDTO.getTitle())
                .orderByDesc(wjAppealPageDTO.getCreateTime(), WjAppeal::getCreateTime)
                .orderByDesc(wjAppealPageDTO.getEndorseCount(), WjAppeal::getEndorseCount);

        // 查询到的参数
        Page<WjAppeal> page1 = page(page, objectQueryWrapper);
        List<WjAppeal> records = page1.getRecords();

        QueryAppealVO queryAppealVO;

        // 获取诉求id集合
        Set<String> ids = records.stream().map(WjAppeal::getAppealId).collect(Collectors.toSet());

        // 获取诉求用户集合
        Set<String> userIds = records.stream().map(WjAppeal::getUserId).collect(Collectors.toSet());
        List<WjUser> users = wjUserService.lambdaQuery()
                .in(CollUtil.isNotEmpty(userIds), WjUser::getUserId, userIds).list();

        //获取每个诉求的点赞数
        List<WjAppealEndorse> appealEndorses = wjAppealEndorseService.lambdaQuery()
                .in(CollUtil.isNotEmpty(ids), WjAppealEndorse::getAppealId, ids).list();
        Map<String, Long> map = appealEndorses.stream()
                .collect(Collectors.groupingBy(WjAppealEndorse::getAppealId, Collectors.counting()));

        // 查询评论总数量
        List<WjAppealComment> wjAppealComments = wjAppealCommentService.lambdaQuery()
                .in(CollUtil.isNotEmpty(ids), WjAppealComment::getAppealId, ids).list();
        Map<String, Long> commentMap = wjAppealComments.stream()
                .collect(Collectors.groupingBy(WjAppealComment::getAppealId, Collectors.counting()));


        //获取每个诉求的素材
        Map<String, List<WjAppealMaterial>> materials = wjAppealMaterialService.lambdaQuery()
                .in(CollUtil.isNotEmpty(ids), WjAppealMaterial::getAppealId, ids)
                .list().stream()
                .collect(Collectors.groupingBy(WjAppealMaterial::getAppealId));

        //获取每个诉求的标签
        Map<String, List<WjAppealTag>> tags = wjAppealTagService.lambdaQuery()
                .in(CollUtil.isNotEmpty(ids), WjAppealTag::getAppealId, ids)
                .list().stream()
                .collect(Collectors.groupingBy(WjAppealTag::getAppealId));

        for (WjAppeal record : records) {
            queryAppealVO = new QueryAppealVO();

            // 赋值给 诉求类
            BeanUtil.copyProperties(record, queryAppealVO);

            // 查询是否点赞
            queryAppealVO.setIsEndorse(appealEndorses.stream().anyMatch(e ->
                    StrUtil.equals(record.getAppealId(), e.getAppealId()) && StrUtil.equals(e.getUserId(), wjAppealPageDTO.getUserId())
            ));

            // 查询评论总数量
            queryAppealVO.setCommentCount(commentMap.get(record.getAppealId()) == null ? 0 : commentMap.get(record.getAppealId()).intValue());

            // 查询点赞总数量
            queryAppealVO.setEndorseCount(map.get(record.getAppealId()) == null ? 0 : map.get(record.getAppealId()).intValue());

            // 查询发帖人信息
            WjUser wjUser = users.stream().filter(e -> e.getUserId().equals(record.getUserId())).findAny().orElseGet(WjUser::new);

            queryAppealVO.setNickName(wjUser.getNickName()).setHeadPortrait(wjUser.getHeadPortrait());

            // 查询帖子相关素材
            queryAppealVO.setAppealMaterial(CollUtil.isEmpty(materials.get(record.getAppealId())) ? Collections.emptyList() : materials.get(record.getAppealId()));

            // 查询帖子相关的 标签
            queryAppealVO.setAppealTag(CollUtil.isEmpty(tags.get(record.getAppealId())) ? Collections.emptyList() : tags.get(record.getAppealId()));


            // end
            queryAppealVOList.add(queryAppealVO);
        }

        BeanUtil.copyProperties(page1, pageData);
        pageData.setRecords(queryAppealVOList);

        return pageData;
    }

    @Override
    public List<QueryNearbyAppealVO> listPageNearbyAppeal(WjAppealPageNearbyDTO wjAppealPageNearbyDTO) {

        // 纬度
        Double latitude = Double.valueOf(wjAppealPageNearbyDTO.getLatitude());
        // 经度
        Double longitude = Double.valueOf(wjAppealPageNearbyDTO.getLongitude());

        // 中心点位置
        Point userPoint = new Point(longitude, latitude);
        // 10 KM范围内
        Distance distanceMetric = new Distance(10, RedisGeoCommands.DistanceUnit.KILOMETERS);
        Circle circle = new Circle(userPoint, distanceMetric);
        // 调用API
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands
                .GeoRadiusCommandArgs.newGeoRadiusArgs()
                // 结果包含距离
                .includeDistance()
                // 结果包含坐标
                .includeCoordinates()
                // 升序
                .sortAscending()
                .limit(wjAppealPageNearbyDTO.getPageQuery().getPageSize());

        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = redisTemplate.boundGeoOps("wjAppeal").radius(circle, args);

        // 最终传过去的值
        List<QueryNearbyAppealVO> list = new ArrayList<>(geoResults.getContent().size());


        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> geoResultList = geoResults.getContent();
        List<String> appealIds = geoResultList.stream().map(e -> e.getContent().getName()).collect(Collectors.toList());

        // 查询到的诉求
        List<WjAppeal> wjAppealList = lambdaQuery().in(CollUtil.isNotEmpty(appealIds), WjAppeal::getAppealId, appealIds)
                .like(StrUtil.isNotBlank(wjAppealPageNearbyDTO.getTitle()), WjAppeal::getTitle, wjAppealPageNearbyDTO.getTitle())
                .list();

        // 发送诉求的 用户信息
        Set<String> userIds = wjAppealList.stream().map(WjAppeal::getUserId).collect(Collectors.toSet());
        List<WjUser> users = wjUserService.lambdaQuery()
                .in(CollUtil.isNotEmpty(userIds), WjUser::getUserId, userIds).list();

        //获取每个诉求的点赞数
        List<WjAppealEndorse> appealEndorses = wjAppealEndorseService.lambdaQuery()
                .in(CollUtil.isNotEmpty(appealIds), WjAppealEndorse::getAppealId, appealIds).list();
        Map<String, Long> map = appealEndorses.stream()
                .collect(Collectors.groupingBy(WjAppealEndorse::getAppealId, Collectors.counting()));

        // 查询评论总数量
        List<WjAppealComment> wjAppealComments = wjAppealCommentService.lambdaQuery()
                .in(CollUtil.isNotEmpty(appealIds), WjAppealComment::getAppealId, appealIds).list();
        Map<String, Long> commentMap = wjAppealComments.stream()
                .collect(Collectors.groupingBy(WjAppealComment::getAppealId, Collectors.counting()));

        //获取每个诉求的素材
        Map<String, List<WjAppealMaterial>> materials = wjAppealMaterialService.lambdaQuery()
                .in(CollUtil.isNotEmpty(appealIds), WjAppealMaterial::getAppealId, appealIds)
                .list().stream()
                .collect(Collectors.groupingBy(WjAppealMaterial::getAppealId));

        //获取每个诉求的标签
        Map<String, List<WjAppealTag>> tags = wjAppealTagService.lambdaQuery()
                .in(CollUtil.isNotEmpty(appealIds), WjAppealTag::getAppealId, appealIds)
                .list().stream()
                .collect(Collectors.groupingBy(WjAppealTag::getAppealId));


        for (GeoResult<RedisGeoCommands.GeoLocation<String>> geoResult : geoResultList) {

            QueryNearbyAppealVO queryNearbyAppealVO = new QueryNearbyAppealVO();

            // 诉求id
            String name = geoResult.getContent().getName();
            // 经纬度
            Point point = geoResult.getContent().getPoint();
            // 距离
            double value = geoResult.getDistance().getValue();
            // 距离单位 （米）
            Metric metric = geoResult.getDistance().getMetric();


            queryNearbyAppealVO.setPoint(point);
            queryNearbyAppealVO.setDistance(value);
            queryNearbyAppealVO.setMetric(metric);

            WjAppeal wjAppeal = wjAppealList.stream().filter(e -> e.getAppealId().equals(name)).findAny().orElseGet(WjAppeal::new);
            BeanUtil.copyProperties(wjAppeal, queryNearbyAppealVO);


            // 查询是否点赞
            queryNearbyAppealVO.setIsEndorse(appealEndorses.stream().anyMatch(e ->
                    StrUtil.equals(name, e.getAppealId()) && StrUtil.equals(e.getUserId(), wjAppealPageNearbyDTO.getUserId())
            ));

            // 评论总数量
            queryNearbyAppealVO.setCommentCount(commentMap.get(name) == null ? 0 : commentMap.get(name).intValue());

            // 查询点赞总数量
            queryNearbyAppealVO.setEndorseCount(map.get(name) == null ? 0 : map.get(name).intValue());

            // 查询发帖人信息
            WjUser wjUser = users.stream().filter(e -> e.getUserId().equals(wjAppeal.getUserId())).findAny().orElseGet(WjUser::new);
            queryNearbyAppealVO.setNickName(wjUser.getNickName()).setHeadPortrait(wjUser.getHeadPortrait());

            // 查询帖子相关素材
            queryNearbyAppealVO.setAppealMaterial(CollUtil.isEmpty(materials.get(name)) ? Collections.emptyList() : materials.get(name));

            // 查询帖子相关的 标签
            queryNearbyAppealVO.setAppealTag(CollUtil.isEmpty(tags.get(name)) ? Collections.emptyList() : tags.get(name));

            list.add(queryNearbyAppealVO);
        }


        return list;
    }


    /**
     * 根据所给的用户id 分页查询他所有的诉求（就是查询我的 诉求）
     *
     * @param wjAppealPageVO
     * @return com.huixi.microspur.commons.page.PageData
     * @Author 叶秋
     * @Date 2020/6/3 22:04
     **/
    @Override
    public PageData ListByUserIdMyAppeal(WjAppealPageDTO wjAppealPageVO) {

        // 最终传过去的值
        PageData pageData = new PageData();

        List<QueryAppealVO> queryAppealVOList = new ArrayList<>();

        // 分页参数
        Page<WjAppeal> page = PageFactory.createPage(wjAppealPageVO.getPageQuery());
        // 查询的条件
        LambdaQueryWrapper<WjAppeal> objectLambdaQueryWrapper = Wrappers.<WjAppeal>lambdaQuery()
                .orderByDesc(WjAppeal::getCreateTime)
                .eq(WjAppeal::getUserId, wjAppealPageVO.getUserId());

        // 查询到的参数
        Page<WjAppeal> page1 = page(page, objectLambdaQueryWrapper);
        List<WjAppeal> records = page1.getRecords();

        QueryAppealVO queryAppealVO;

        // 诉求id集合
        Set<String> ids = records.stream().map(WjAppeal::getAppealId).collect(Collectors.toSet());

        // 获取诉求用户集合
        Set<String> userIds = records.stream().map(WjAppeal::getUserId).collect(Collectors.toSet());
        List<WjUser> users = wjUserService.lambdaQuery()
                .in(CollUtil.isNotEmpty(ids), WjUser::getUserId, userIds).list();

        //获取每个用户的点赞数
        List<WjAppealEndorse> appealEndorses = wjAppealEndorseService.lambdaQuery()
                .in(CollUtil.isNotEmpty(ids), WjAppealEndorse::getAppealId, ids).list();
        Map<String, Long> map = appealEndorses.stream()
                .collect(Collectors.groupingBy(WjAppealEndorse::getAppealId, Collectors.counting()));

        // 查询评论总数量
        List<WjAppealComment> wjAppealComments = wjAppealCommentService.lambdaQuery()
                .in(CollUtil.isNotEmpty(ids), WjAppealComment::getAppealId, ids).list();
        Map<String, Long> commentMap = wjAppealComments.stream()
                .collect(Collectors.groupingBy(WjAppealComment::getAppealId, Collectors.counting()));

        //获取每个诉求的素材
        Map<String, List<WjAppealMaterial>> materials = wjAppealMaterialService.lambdaQuery()
                .in(CollUtil.isNotEmpty(ids), WjAppealMaterial::getAppealId, ids)
                .list().stream()
                .collect(Collectors.groupingBy(WjAppealMaterial::getAppealId));

        //获取每个诉求的标签
        Map<String, List<WjAppealTag>> tags = wjAppealTagService.lambdaQuery()
                .in(CollUtil.isNotEmpty(ids), WjAppealTag::getAppealId, ids)
                .list().stream()
                .collect(Collectors.groupingBy(WjAppealTag::getAppealId));


        for (WjAppeal record : records) {
            queryAppealVO = new QueryAppealVO();

            // 查询是否点赞
            queryAppealVO.setIsEndorse(appealEndorses.stream().anyMatch(e ->
                    StrUtil.equals(record.getAppealId(), e.getAppealId()) && StrUtil.equals(e.getUserId(),
                            wjAppealPageVO.getUserId())
            ));

            // 查询评论总数量
            record.setCommentCount(commentMap.get(record.getAppealId()) == null ? 0 : commentMap.get(record.getAppealId()).intValue());

            // 查询点赞总数量
            record.setEndorseCount(map.get(record.getAppealId()) == null ? 0 : map.get(record.getAppealId()).intValue());


            // 查询发帖人信息
            WjUser wjUser = users.stream().filter(e -> e.getUserId().equals(record.getUserId())).findAny().orElseGet(WjUser::new);


            queryAppealVO.setNickName(wjUser.getNickName()).setHeadPortrait(wjUser.getHeadPortrait());

            // 查询帖子相关素材
            queryAppealVO.setAppealMaterial(CollUtil.isEmpty(materials.get(record.getAppealId())) ? Collections.emptyList() : materials.get(record.getAppealId()));

            // 查询帖子相关的 标签
            queryAppealVO.setAppealTag(CollUtil.isEmpty(tags.get(record.getAppealId())) ? Collections.emptyList() : tags.get(record.getAppealId()));

            // 赋值给 诉求类
            BeanUtil.copyProperties(record, queryAppealVO);


            // end
            queryAppealVOList.add(queryAppealVO);

        }


        BeanUtil.copyProperties(page1, pageData);
        pageData.setRecords(queryAppealVOList);

        return pageData;

    }


    /**
     * 判断是否是自己发布的
     *
     * @param appealId 诉求id
     * @param userId   用户id
     * @return java.lang.Boolean
     * @Author 叶秋
     * @Date 2020/7/1 21:06
     **/
    @Override
    public Boolean judgeAppealIsMe(String appealId, String userId) {

        QueryWrapper<WjAppeal> wjAppealQueryWrapper = new QueryWrapper<>();
        wjAppealQueryWrapper.eq("appeal_id", appealId).eq("user_id", userId);

        WjAppeal one = getOne(wjAppealQueryWrapper);

        if (ObjectUtil.isNotNull(one)) {
            return true;
        }


        return false;
    }


    /**
     * 校验于此诉求沟通的人是否已满
     *
     * @param appealId 诉求id
     * @return java.lang.Boolean
     * @Author 叶秋
     * @Date 2020/7/9 21:44
     **/
    @Override
    public Boolean verifyAppealFull(String appealId) {

        QueryWrapper<WjChat> wjChatQueryWrapper = new QueryWrapper<>();
        wjChatQueryWrapper.eq("appeal_id", appealId);

        WjChat one = wjChatService.getOne(wjChatQueryWrapper);

        if (ObjectUtil.isNotNull(one)) {
            return true;
        }


        return false;
    }


}
